package com.wngbms.netty.seatdemo.client;

import com.alibaba.fastjson.JSON;
import com.wngbms.netty.seatdemo.bean.OwnerInfo;
import com.wngbms.netty.seatdemo.comm.*;
import com.wngbms.netty.seatdemo.message.BaseHeader;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;

@Slf4j
public class SimpleSocketClient {

    public static ClientSeatInMessage clientSeatInMessage;

    public static void main(String[] args) throws IOException, InterruptedException {

        CountDownLatch countDownLatch = new CountDownLatch(2);

        Socket socket = new Socket("127.0.0.1", 8090);

        OutputStream outputStream = socket.getOutputStream();
        InputStream inputStream = socket.getInputStream();

        new Thread(() -> {
            try {
//                sendConnect(outputStream);
//                sleep(1000);
//                sendHeartbeat(outputStream);
//                sleep(1000);
//                sendOwnerSearch(outputStream);
//                sleep(1000);
//                uploadFile(outputStream);
//                sleep(1000);
//                sendHeartbeat(outputStream);
//                sleep(1000);
//                reqDownloadFile(outputStream);
//                sleep(1000);
//                sendHeartbeat(outputStream);
//                sleep(1000);
//                reqDownloadFile(outputStream);
//                sleep(1000);
//                sendOwnerSearch(outputStream);
//                sleep(1000);
//                reqDownloadFile(outputStream);
//                sleep(1000);
//                sendHeartbeat(outputStream);
//                sleep(1000);
//                reqDownloadFile(outputStream);
//                sleep(1000);
//                sendOwnerSearch(outputStream);
//                sleep(1000);
//                uploadFile(outputStream);
                echo(outputStream);
                log.info("发送测试完毕");
                countDownLatch.countDown();
//                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
                receiveData(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

        countDownLatch.await();
        socket.close();
        log.info("客户端关闭");
    }

    public static void receiveData(InputStream inputStream) throws IOException {
        byte[] buf = new byte[4096];
        int len, writableIndex = 0, readableIndex = 0;

        while ((len = inputStream.read(buf, writableIndex, buf.length - writableIndex)) > 0) {
            writableIndex += len;

            do {
                readableIndex = parse(buf, readableIndex, writableIndex - readableIndex);
            } while (readableIndex < writableIndex);

            sleep(10000);

            readableIndex = writableIndex = 0;
        }
    }

    public static int parse(byte[] buf, int readableIndex, int readableLength) throws IOException {
        if (clientSeatInMessage == null) {
            clientSeatInMessage = new ClientSeatInMessage();
            BaseHeader baseHeader = new BaseHeader();
            clientSeatInMessage.setBaseHeader(baseHeader, false);
        }

        BaseHeader baseHeader = clientSeatInMessage.getBaseHeader();
        if (!baseHeader.isFinish()) {
            readableIndex += baseHeader.writeHeader(buf, readableIndex, readableLength);
        } else {
            clientSeatInMessage.parsed();
            readableIndex += clientSeatInMessage.writeBody(buf, readableIndex, readableLength);
        }

        if (clientSeatInMessage.parsed() && clientSeatInMessage.finished()) {
            ClientSeatInMessage req = clientSeatInMessage;
            clientSeatInMessage = null;
            doBizServ(req);
        }

        return readableIndex;
    }

    public static void doBizServ(ClientSeatInMessage req) {
        BaseHeader baseHeader = req.getBaseHeader();

        CmdType cmdType = baseHeader.getCmdType();
        switch (cmdType) {
            case EVENT:
                log.info("事件信息:{}", new String(req.getBody(), StandardCharsets.UTF_8));
                break;
            case HEARTBEAT:
                log.info("接收到服务端心跳");
                break;
            case EXTRA_INFO:
                log.info("补充额外信息:{}", new String(req.getBody(), StandardCharsets.UTF_8));
                break;
            case OWNER_SEARCH:
                log.info("业主信息查询响应:{}", new String(req.getBody(), StandardCharsets.UTF_8));
                break;
            case HANGUP:
                log.info("接收到对方挂断指令:{}", new String(req.getBody(), StandardCharsets.UTF_8));
//                sleep(500);
//                log.info("关闭连接");
                break;
            case BINARY_TEST_DOWNLOAD:
                log.info("文件下载测试完毕: {}", req.getFile().getAbsolutePath());
                break;
            case ECHO:
                log.info("echo:{}", new String(req.getBody(), StandardCharsets.UTF_8));
                break;
            default:
                log.info("unknown cmd type");
        }
    }

    public static void echo(OutputStream outputStream) throws IOException {
        for (int i = 0; i < 5000; i++) {
            String uuid = UUID.randomUUID().toString();
            String s = "苹果手机就是好用, 万物基于MIUI Windows 11 " + uuid;
            byte[] bytes = s.getBytes(StandardCharsets.UTF_8);

            BaseHeader baseHeader = BaseHeader.build(MagicVersion.V1,
                    CmdType.ECHO, BodyType.TEXT,
                    EncryptionType.NON, ReqOrResp.REQ,
                    bytes.length);

            byte[] header = baseHeader.getHeader();

            write(header, outputStream);
            write(bytes, outputStream);
            outputStream.flush();
        }
    }

    public static void write(byte[] buf, OutputStream outputStream) throws IOException {
        byte[] b = new byte[1];
        for (int i = 0; i < buf.length; i++) {
            b[0] = buf[i];
            outputStream.write(b);
        }
    }

    public static void reqDownloadFile(OutputStream outputStream) throws IOException {
        BaseHeader baseHeader = BaseHeader.build(MagicVersion.V1, CmdType.BINARY_TEST_DOWNLOAD, BodyType.NON, EncryptionType.NON, ReqOrResp.REQ, 0);
        byte[] header = baseHeader.getHeader();

        outputStream.write(header);
        outputStream.flush();
    }

    public static void uploadFile(OutputStream outputStream) throws IOException {
        String filePath = "J:\\readme.txt";
//        String filePath = "J:\\aDrive.exe";
//        String filePath = "J:\\mysql-5.7.17.msi";
        File file = new File(filePath);
        if (!file.exists()) {
            log.info("{}文件不存在", filePath);
            return;
        }

        long length = file.length();
        log.info("文件长度:{}", length);

        BaseHeader baseHeader = BaseHeader.build(MagicVersion.V1, CmdType.BINARY_TEST_UPLOAD, BodyType.BINARY, EncryptionType.NON, ReqOrResp.REQ, (int) length);
        byte[] header = baseHeader.getHeader();

        outputStream.write(header);

        FileInputStream fis = new FileInputStream(file);
        byte[] buf = new byte[4096];
        int len;
        while ((len = fis.read(buf)) > 0) {
            outputStream.write(buf, 0, len);
        }
        outputStream.flush();

        log.info("文件上传完成");
        fis.close();
    }

    public static void sendOwnerSearch(OutputStream outputStream) throws IOException {
        OwnerInfo ownerInfo = new OwnerInfo();
        ownerInfo.setName("霍尊");
        String jsonString = JSON.toJSONString(ownerInfo);
        byte[] bytes = jsonString.getBytes(StandardCharsets.UTF_8);
        BaseHeader baseHeader = BaseHeader.build(MagicVersion.V1, CmdType.OWNER_SEARCH, BodyType.JSON, EncryptionType.NON, ReqOrResp.REQ, bytes.length);
        byte[] header = baseHeader.getHeader();

        outputStream.write(header);
        outputStream.write(bytes);
        outputStream.flush();
    }

    public static void sendHeartbeat(OutputStream outputStream) throws IOException {
        BaseHeader baseHeader = BaseHeader.build(MagicVersion.V1, CmdType.HEARTBEAT, BodyType.NON, EncryptionType.NON, ReqOrResp.REQ, 0);
        byte[] header = baseHeader.getHeader();

        outputStream.write(header);
        outputStream.flush();
    }

    public static void sendConnect(OutputStream outputStream) throws IOException {
        String userId = "rxseat01";
        byte[] bytes = userId.getBytes(StandardCharsets.UTF_8);
        BaseHeader baseHeader = BaseHeader.build(MagicVersion.V1, CmdType.CONNECT, BodyType.TEXT, EncryptionType.NON, ReqOrResp.REQ, bytes.length);
        byte[] header = baseHeader.getHeader();

        outputStream.write(header);
        outputStream.write(bytes);
        outputStream.flush();
    }

    static void sleep(long t) {
        try {
            Thread.sleep(t);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
